﻿using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System;
using System.IO;

public class ResourceManager : Singleton<ResourceManager> {

	public const string ASSETPATH = "AssetBundle";

	public const string RES_INFO_NAME = "ResInfo.txt";

	public const string UPDATE_NAME = "Update.txt";

	private Dictionary<int, Resource> cachedResourceMap;

	private ResourcePackerInfoSet m_resourcePackerInfoSet;

	private static int s_frameCounter;

	private int m_clearUnusedAssetsExecuteFrame;

	private bool m_clearUnusedAssets;

	public static string PersistentAssetPath {
		get {
//			#if LOCAL_DEBUG
//			string p = FileTools.GetFullDirectory(Application.dataPath);
//			return FileTools.CombinePath (p, "AssetBundle/Android");
//			#else
			return FileTools.CombinePath (Application.persistentDataPath, ASSETPATH);
//			#endif
		}
	}

	public static string ResInfoFilePath {
		get {
//			#if LOCAL_DEBUG
//			string p = FileTools.GetFullDirectory(Application.dataPath);
//			return FileTools.CombinePath (p, "AssetBundle/Android/" + RES_INFO_NAME);
//			#else
			return FileTools.CombinePath (PersistentAssetPath, RES_INFO_NAME);
//			#endif
		}
	}

	public static string UpdateFilePath {
		get {
			return FileTools.CombinePath (PersistentAssetPath, UPDATE_NAME);
		}
	}

	public override void Init ()
	{
		base.Init ();
		this.m_resourcePackerInfoSet = null;
		cachedResourceMap = new Dictionary<int, Resource> ();
	}

	public Dictionary<int, Resource> GetCachedResourceMap()
	{
		return this.cachedResourceMap;
	}

	public void LoadResourcePackerInfoSet() {
		if (this.m_resourcePackerInfoSet != null) {
			this.m_resourcePackerInfoSet.Dispose ();
			this.m_resourcePackerInfoSet = null;
		}

		if (FileTools.IsFileExist (ResInfoFilePath)) {
			string info = File.ReadAllText (ResInfoFilePath);
			this.m_resourcePackerInfoSet = new ResourcePackerInfoSet ();
			this.m_resourcePackerInfoSet.Read (info);
			this.m_resourcePackerInfoSet.CreateResourceMap ();
		}
	}

	public void AddPackerInfoSet(string info) {
		if (this.m_resourcePackerInfoSet != null) {
			this.m_resourcePackerInfoSet.AddInfo (info);
		}
	}

	public void CustomUpdate()
	{
		s_frameCounter++;
		if (this.m_clearUnusedAssets && (this.m_clearUnusedAssetsExecuteFrame == s_frameCounter))
		{
			this.ExecuteUnloadUnusedAssets();
			this.m_clearUnusedAssets = false;
		}
	}

	public bool CheckCachedResource(string fullPathInResources)
	{
		string s = FileTools.EraseExtension(fullPathInResources);
		Resource hResource = null;
		return this.cachedResourceMap.TryGetValue(s.JavaHashCodeIgnoreCase(), out hResource);
	}

    public Resource GetResource(string fullPathResource, Type resourceContentType, enResourceType resourceType, bool needCached = false, bool unloadBelongedAssetBundleAfterLoaded = false)
    {
        //Debug.LogError (fullPathResource);
        if (string.IsNullOrEmpty(fullPathResource))
        {
            return new Resource(0, string.Empty, null, resourceType, unloadBelongedAssetBundleAfterLoaded);
        }
        string text = FileTools.EraseExtension(fullPathResource);
        int num = text.JavaHashCodeIgnoreCase();
        Resource resource = null;
        if (cachedResourceMap.TryGetValue(num, out resource))
        {
            if (resource.m_resourceType != resourceType)
            {
                resource.m_resourceType = resourceType;
            }
            return resource;
        }
        resource = new Resource(num, fullPathResource, resourceContentType, resourceType, unloadBelongedAssetBundleAfterLoaded);
        try
        {
            this.LoadResource(resource);
        }
        catch (Exception ex)
        {
            Debug.AssertFormat(false, "Failed Load Resource {0}", new object[]
            {
                text
            });
            throw ex;
        }
        if (needCached)
        {
            this.cachedResourceMap.Add(num, resource);
        }
        return resource;
    }

    // 异步加载资源   目前有多次调用但资源还未加载完成的情况没处理
    // 只是简单测试Resource加载方式的异步加载，ab加载还未实现
    public void GetResourceAsync(string fullPathResource, Type resourceContentType, enResourceType resourceType, System.Action<Resource> callback, bool needCached = false, bool unloadBelongedAssetBundleAfterLoaded = false)
    {
        if (callback != null)
        {
            callback(GetResource(fullPathResource, resourceContentType, resourceType, needCached, unloadBelongedAssetBundleAfterLoaded));
        }
        return;

        if (string.IsNullOrEmpty(fullPathResource))
        {
            if (callback != null)
            {
                callback(new Resource(0, string.Empty, null, resourceType, unloadBelongedAssetBundleAfterLoaded));
            }
            return;
        }
        string text = FileTools.EraseExtension(fullPathResource);
        int num = text.JavaHashCodeIgnoreCase();
        Resource resource = null;
        if (cachedResourceMap.TryGetValue(num, out resource))
        {
            if (resource.m_resourceType != resourceType)
            {
                resource.m_resourceType = resourceType;
            }
            if (callback != null)
            {
                callback(resource);
            }
            return;
        }
        resource = new Resource(num, fullPathResource, resourceContentType, resourceType, unloadBelongedAssetBundleAfterLoaded, callback);
        try
        {
            this.LoadResourceAsync(resource);
        }
        catch (Exception ex)
        {
            Debug.AssertFormat(false, "Failed Load Resource {0}", new object[]
            {
                text
            });
            throw ex;
        }
        if (needCached)
        {
            this.cachedResourceMap.Add(num, resource);
        }
    }

    #region load
    private void LoadResource(Resource resource)
	{
		ResourcePackerInfo resourceBelongedPackerInfo = this.GetResourceBelongedPackerInfo(resource);
		if (resourceBelongedPackerInfo != null)
		{
			if (!resourceBelongedPackerInfo.IsAssetBundleLoaded())
			{
				resourceBelongedPackerInfo.LoadAssetBundle(PersistentAssetPath);
			}
			resource.LoadFromAssetBundle(resourceBelongedPackerInfo);
			if (resource.m_unloadBelongedAssetBundleAfterLoaded)
			{
				resourceBelongedPackerInfo.UnloadAssetBundle(false);
			}
		}
		else
        {
            resource.Load();
        }
    }

    // 只是简单测试Resource加载方式的异步加载，ab加载还未实现
    private void LoadResourceAsync(Resource resource)
    {
        resource.LoadAsync();
    }

    private ResourcePackerInfo GetResourceBelongedPackerInfo(Resource resource)
	{
		if (this.m_resourcePackerInfoSet != null)
		{
			return this.m_resourcePackerInfoSet.GetResourceBelongedPackerInfo(resource.m_key);
		}
		return null;
	}

	public ResourcePackerInfo GetResourceBelongedPackerInfo(string fullPathInResources)
	{
		if (string.IsNullOrEmpty(fullPathInResources))
		{
			return null;
		}
		if (this.m_resourcePackerInfoSet != null)
		{
			return this.m_resourcePackerInfoSet.GetResourceBelongedPackerInfo(FileTools.GetFullDirectory(fullPathInResources).JavaHashCodeIgnoreCase());
		}
		return null;
	}

	public ResourcePackerInfo GetPackerInfoByName(string name)
	{
		if (string.IsNullOrEmpty(name))
		{
			return null;
		}
		if (this.m_resourcePackerInfoSet != null)
		{
			return this.m_resourcePackerInfoSet.GetPackerInfo(name);
		}
		return null;
	}
	#endregion

	#region remove
	public void RemoveCachedResource(string fullPathInResources)
	{
		string s = FileTools.EraseExtension(fullPathInResources);
		int key = s.JavaHashCodeIgnoreCase();
		Resource cResource = null;
		if (this.cachedResourceMap.TryGetValue(key, out cResource))
		{
			cResource.Unload();
			this.cachedResourceMap.Remove(key);
		}
	}

	public void RemoveCachedResources(enResourceType resourceType, bool clearImmediately = true)
	{
		List<int> list = new List<int>();
		Dictionary<int, Resource>.Enumerator enumerator = this.cachedResourceMap.GetEnumerator();
		while (enumerator.MoveNext())
		{
			KeyValuePair<int, Resource> current = enumerator.Current;
			Resource value = current.Value;
			if (value.m_resourceType == resourceType)
			{
				value.Unload();
				list.Add(value.m_key);
			}
		}
		for (int i = 0; i < list.Count; i++)
		{
			this.cachedResourceMap.Remove(list[i]);
		}
		if (clearImmediately)
		{
			this.UnloadAllAssetBundles();
			this.UnloadUnusedAssets();
		}
	}

	public void RemoveCachedResources(enResourceType[] resourceTypes)
	{
		for (int i = 0; i < resourceTypes.Length; i++)
		{
			this.RemoveCachedResources(resourceTypes[i], false);
		}
		this.UnloadAllAssetBundles();
		this.UnloadUnusedAssets();
	}

	public void RemoveAllCachedResources()
	{
		this.RemoveCachedResources((enResourceType[])Enum.GetValues(typeof(enResourceType)));
	}
	#endregion

	#region unload
	public void UnloadBelongedAssetbundle(string fullPathInResources)
	{
		ResourcePackerInfo resourceBelongedPackerInfo = this.GetResourceBelongedPackerInfo(fullPathInResources);
		if (resourceBelongedPackerInfo != null && resourceBelongedPackerInfo.IsAssetBundleLoaded())
		{
			resourceBelongedPackerInfo.UnloadAssetBundle(false);
		}
	}

	public void UnloadUnusedAssets()
    {
        this.m_clearUnusedAssets = true;
		this.m_clearUnusedAssetsExecuteFrame = ResourceManager.s_frameCounter + 1;
	}

	private void ExecuteUnloadUnusedAssets()
    {
        Resources.UnloadUnusedAssets();
		GC.Collect();
	}

	private void UnloadAllAssetBundles()
	{
		if (this.m_resourcePackerInfoSet != null)
		{
			this.m_resourcePackerInfoSet.UnloadAll ();
		}
	}
	#endregion

}
